Niels Holst, Aarhus University, Denmark, 25 May 2023.
The documentation comes with R script that demonstrate the equations and logic of the model. Before you run any of the scripts, you need to change the R work folder. This is defined in the setup.R script, which begins like this:
1# Prelude2setwd("~/QDev/UniSim3/input/models/vg")3library(ggplot2)4library(ggpubr)5library(plyr)6library(reshape2)7...
Edit the file path in the sewtd(...) statement to point to the folder where you put the R scripts.
Make sure the four libraries (loaded in lines 3 to 6) are all installed on your computer.
Run the setup.R script once before running any of the other scripts.
The model is updated iteratively in a loop at a time step of
Model components are updated in the following order:
Calender updates current date and time.
Outdoors updates climatic variables based on the weather file. Readings from the weather file are interpolated linearly to estimate values for the current date and time. If the weather file does not contain a Tsky column, sky temperature is estimated by a model. Soil temperature is currently roughly modelled (this needs an update).
Greenhouse construction contains the dimensions of the greenhouse and a description of each of the six greenhouse faces (traditionally, glass, see cover layer).
Setpoints are defined for the green house actuators, such as growth lights, heat pipes, ventilation, screens and CO2 diffusers, to keep indoors climate within the desired bounds.
Controllers use the setpoints to compute the settings of actuators.
Actuators represent growth lights, heat pipes, ventilation, screens, CO2 diffusers, etc., which control the greenhouse climate. They are governed by the setpoints via the controllers.
Indoors holds the greenhouse compartments of layers and volumes and keeps their state variables updated, reflecting the current outdoors driving variables and actuator settings.
Output writes the chosen variables to the output file.
The simulation begins 24 hours before the declared beginning of the simulation. This allows model state variables to attain sensible initial values. Here is a possible layout of a boxscript. The lonely : characters denote left-out lines:
xxxxxxxxxx381Simulation sim {2Box global {3&beginDate = 2022/08/014:5}6Calendar calendar {7.latitude = 55.48.longitude = 10.49.begin = global[beginDate] - 110.end = 2022/08/1511.timeStep = 1512.timeUnit = "m"13}14Outdoors outdoors {15:16}17Box construction {18:19}20Box setpoints {21:22}23Controllers controllers {24:25}26Box actuators {27:28}29Box indoors {30:31}32OutputR output {33:34OutputSelector {35.beginDateTime = global[beginDate]36}37}38}
A global box is declared to hold global settings, i.e., parameters that serve as inputs to one or more of the boxes further down in the boxscript. A beginDate port is created (the ampersand & means that a new port is created) to start the simulation on 1 August 2022. The calendar actually starts one day before, as set by its begin port (line 9); the initial period . denotes an existing input port. At the very end of the boxscript, an OutputSelector box asks for the output to be written starting on 1 August (line 35). In effect, the initial extra day's output will be discarded. The simulation will run until the final date end set by the calendar box; the time step has been set to 15 minutes (lines 10-11).
The greenhouse consists of

From these parameters we can derive several measures of greenhouse geometry. The area of a single face, either side, end or roof, is
from which follows the total area of side, end and roof faces, and the total cover area (all in m2),
The ground area (m2) enclosed by the greenhouse is
and the volume contained (m3) is
Further useful measures are the cover/area ratio
and the volumetric area index
Furthermore, the density of air
The equations above have been coded in the greenhouse-geometry.R script::
x1n = 252w = 43L = 1004h = 3.55u = 2667A_side_ 350.0008A_end_ 15.7539A_roof_ 218.3731011A_side 700.00012A_end 787.67413A_roof 10918.65014A_cover 12406.3251516A_gh 10000.00017V_gh 39383.71118cover_per_ground 1.24119avg_height 3.93820C_gh 4780.395
In boxscripts, greenhouse dimensions are set in the geometry box inside construction:
xxxxxxxxxx101Box construction{2vg::Geometry geometry{3.numSpans = 254.spanWidth = 45.length = 1006.height = 3.57.roofPitch = 268}9:10}
The greenhouse model holds three volumes: indoors, outdoors and soil. The indoors holds state variables, while the outdoors and soil hold driving variables. All three hold temperature
Volumes may exchange heat and humidity with neighbouring volumes and layers.
Besides layers the greenhouse and its environment is conceptualised as a stack of
sky
cover (e.g., glass)
screen
growth light
plant canopy
heat pipe
floor
Depending on the scenario, layers can be removed or added (e.g., additional screen layers or a table layer ). All layers, whether they are horisontal or inclined, uniform or heterogeneous, thick or thin, are simplified to describe an average 1m2 ground area of the greenhouse. For screens this area will vary according to what degree they are drawn. Where the unit m2 is used, it always refers to m2 ground. Sometimes it is spelled out "m2 ground" to avoid confusion.
The radiative properties of each layer is parameterised for three intervals of the spectrum:
PAR (μmol/m2/s)
short-wave radiation (W/m2)
long-wave radiation (W/m2)
PAR is a subset of the short-wave radiation. The PAR budget is resolved only to compute how much is absorbed by the plant canopy. Its quantum units reflect this purpose. In contrast, the short- and long-wave radiation both contribute to the radiative exchange of heat among layers. Remember that W = J/s.

Each layer
The superscript
Layers are further described by their area-specific heat capacity (
The construction box holds two child boxes, geometry and shelter. The shelter box holds definitions of different cover and screen materials inside the covers and screens box, respectively. In the boxscript below, one kind of cover is defined (named glass) and four kinds of screens (named energy, shade1, shade2 and blackout). You can name the materials as you want.
The faces box (lines 67-98) holds the named materials of cover and screens for each of the six shelter faces. There may be more than one layer of screens installed. These screen layers are written in sequence starting nearest the glass. For example, with up to three layers installed on a face, you might have faces with screens specified as energy+shade1+blackout, none+shade2+blackout, energy+none+blackout or none+none+blackout, or any other combination of screen materials defined by the names of the shelter/screens/* boxes. All six faces must have the same number of screens defined. If a face has no screen in a certain layer, it is written as none.
xxxxxxxxxx1061Box construction{2vg::Geometry geometry{3.numSpans = 254.spanWidth = 45.length = 1006.height = 3.57.roofPitch = 268}9Box shelter {10UWind Utop {11}12Box covers {13Cover glass {14.swReflectivityTop = 0.115.swTransmissivityTop = 0.816.swReflectivityBottom = 0.117.swTransmissivityBottom = 0.818.lwReflectivityTop = 0.1519.lwTransmissivityTop = 0.2020.lwReflectivityBottom = 0.1521.lwTransmissivityBottom = 0.2022.Utop = ../../Utop[value]23.Ubottom = 1.224.heatCapacity = 840025.swReflectivityChalk = actuators/chalk[swReflectivity]26.lwReflectivityChalk = actuators/chalk[lwReflectivity]27}28}29Box screens {30Screen energy {31.swReflectivityTop = 0.9332.swTransmissivityTop = 0.033:34.Utop = 1.235.Ubottom = 1.236.heatCapacity = 8037.state = actuators/screens/energy[state]38}39Screen shade1 {40.swReflectivityTop = 0.7041.swTransmissivityTop = 0.2042:43.Utop = 1.244.Ubottom = 1.245.heatCapacity = 80.46.state = actuators/screens/shade[state]47}48Screen shade2 {49.swReflectivityTop = 0.8050.swTransmissivityTop = 0.1051:52.Utop = 1.153.Ubottom = 1.154.heatCapacity = 120.55.state = actuators/screens/shade[state]56}57Screen blackout {58.swReflectivityTop = 0.0559.swTransmissivityTop = 0.060:61.Utop = 1.262.Ubottom = 1.263.heatCapacity = 200.64.state = actuators/screens/blackout[state]65}66}67Box faces {68Box roof1 {69&cover = "glass"70&screens = "energy+shade1+blackout"71&area = ../../geometry[roofArea]/272&weight = 173}74Box roof2 {75&cover = "glass"76&screens = "energy+shade1+blackout"77&area = ../../geometry[roofArea]/278&weight = 179}80Box side1 {81&cover = "glass"82&screens = "none+shade2+blackout"83&area = ../../geometry[sideArea]/284&weight = 185}86Box side2 {87&cover = "glass"88&screens = "none+none+blackout"89&area = ../../geometry[sideArea]/290&weight = 0.591}92Box end1 {93&cover = "glass"94&screens = "none+none+blackout"95&area = ../../geometry[endArea]/296&weight = 0.297}98Box end2 {99&cover = "glass"100&screens = "energy+none+blackout"101&area = ../../geometry[endArea]/2102&weight = 0.2103}104}105}106}
Any layer has 11 input ports defining its basic radiative properties (lines 14-21), Cover boxes holds two additional inputs (lines 25-26) specifying the current status of whitening ('chalk'), which is provided by the chalk actuator. In a similar vein, Screen boxes hold one additional input state, which refers to a screen actuator. From the code above, you can infer that in this model there are three screen actuators:
actuators/screens/energywhich determines the position of the energy screen
actuators/screens/shade which determines the position of the shade1 and shade2 screens
actuators/screens/blackout which determines the position of the blackout screen
In addition to cover and screens, each face has a weight parameter that is used when calculating the average radiative properties of the greenhouse cover and each screen layer. The settings above suggest that side2 is north-facing.
Radiation might be emitted by a layer, both down- and upwards, in terms of PAR (
where
The emitted radiation is intercepted by neighbouring layers, its ultimate fate determined by the characteristics (absorptivity, reflectivity, transmissivity) of the whole stack of layers, as worked out in the energy budget. The net radiative absorption of a layer (i.e. its absorption minus emission) is denoted by (
The exchange of heat between layer
The convective/conductive heat absorbed by layer
where the temperature of the volume above and below layer
Advective heat transfer occurs when outdoors air replaces indoors air. This is due to intentional ventilation as well as inadvertent leakage. We formulate the ventilation rate as, "how many times greenhouse air is replaced per hour"
During a time step
Integration gives us
The relation is illustrated by the advection.R script with

To calculate the change in indoors temperature
With a time step of, for example
The change in indoors absolute humidity
Eq.
The maximum ventilation rate
with discharge coefficients for wind
Latent heat is related to the phase change between water in the gas and the liquid phase. The phase change costs (by evaporation) or releases (by condensation) energy according to the latent heat of water vapourisation
In the model, transpiration cools the canopy and condensation heats the cover. The transpired water adds to air humidity, which is then considered to have increased its content of latent heat. Water vapour bears latent heat in the sense that if it condenses, the heat used for the initial phase change from liquid to gas, will be used in the phase change back from gas to liquid.
The model does not include the cooling effect of water evaporating from wet surfaces, nor the wetting and drying of screens.
The radiation emitted downwards from the sky includes
While
Sky emissivity
Sky temperature
where
Sky reflectivity
The cover layer is commonly made out of glass with the following typical characteristics:
| Glass properties | PAR | Short-wave | Long-wave |
|---|---|---|---|
| 0.1 | 0.1 | 0.9 | |
| 0.1 | 0.1 | 0.1 | |
| 0.8 | 0.8 | 0.0 |
In general, the six faces of the greenhouse may carry different covers with different radiative properties. For the cover layer as a whole, each radiative parameter is summarised as the average over all faces, weighed by face area.
The density of window glass is typically
The cover emits long-wave radiation symmetrically down and up according to the Stefan-Boltzmann Law (eq.
The
where
Since the six cover faces may differ in their characteristics, we may need to average their parameter values. Some examples applying the equations below of are shown in the cover-averaging.R script.
Let's assume that the two end faces differ from the other four faces; we set
For the radiative parameters (
where subscript
With the numbers above and the illustrative greenhouse dimensions we have (with parameters pair-wise in the order: roofs, sides, ends)
which gives us the averaged values,
The roof faces are dominating by their size; hence the average parameter values are close to the roof values. If we change all weights to one
Heat capacity is averaged to apply to the greenhouse ground area (eq.
where
Using the the illustrative greenhouse dimensions we have
which gives us
As expected, this heat capacity is larger than the one calculated for and all-glass greenhouse
The
It follows that conductances are simply additive. Thus the conductance of the greenhouse cover as a whole is arrived at by the sum of the faces. Relating this to the ground area of the greenhouse
As for heat capacity (eq.
For example, If the cover material has
from which follows
The reason why the average
Screens are often constructed with asymmetric radiative properties. Here, for example, are the radiative parameters of a polyester screen with an aluminium surface on the upper side (from Bailey 1981):
| Screen properties | Long-wave radiation |
|---|---|
| 0.57 | |
| 0.43 | |
| 0.07 | |
| 0.93 | |
| 0.0 |
The values in the table are for long-wave radiation only. They are most likely different for short-wave radiation but documentation for the physical characteristics of screens are hard to come by; manufacturers seem reluctant to provide the information.
Screens may be more or less drawn . If we denote how much a curtain is drawn by its position
Screens may be constructed of composite materials which complicates the calculation of their heat capacity. For the screen exemplified here, we found quite close values of
This calculation implies that all six greenhouses faces are equally covered with the same screen. If that is not the case then
The screen emits long-wave radiation according to the Stefan-Boltzmann Law (eq.
The averaging of screens in a layer follows the same principles as cover averaging, except that screens also have a position
Thus for the radiative parameter
with transmissivity as in eq.
The heat capacity and U-value of screens is assumed to be in effect only when they are drawn. Hence we get (cf. eqs.
and the total U-value of the screen layer
Some examples are shown in the screen-averaging.R script.
Screen layers function just like any other layer (see Layers). Thus there is need for special mechanisms to account for screen layering.
Lamps are installed to provide growth light. Even so, their production of heat is a significant side effect. Light is traditionally emitted downwards from a position above the canopy. If the installed lamp power (including any ballast or driver needed by the lamps) is
Lamps may loose efficiency with age, which is reflected in a reduced
Energy is dissipated from the lamps by three routes: short-waved and long-waved radiation and convection. The proportions are denoted
The growth light layer has a 100% transmissivity (
Stanghellini (1987 ,eq. 2.1) sets up the following energy balance for the plant canopy
The equation states (in her notation) that the energy of net radiation absorbed by the canopy
convective heat loss to the greenhouse air
heat for the evaporation of water needed for transpiration
photosynthate production
heat storage in the canopy
Like Stanghellini we will ignore
Goudriaan (1977) provides equations (his eqs. 2.21 and 2.26) to calculate the reflectivity of a plant canopy with leaf area index
The original eq. 2.26 includes the reflectivity of the surface underneath the canopy (the floor in our case). However, we will resolve the distribution of radiation among the greenhouse layers otherwise. Consequently, we can set the reflectivity of the underlying surface in the original equation to zero. Thus we get the reflectivity of the canopy, which is symmetric for up- and down-going radiation, based on his eq.2.26,
where superscript
The absorptivity of the canopy is simply
and the transmissivity
The plant-canopy-layer.R script shows how the parameters change with increasing leaf area index for short-wave (

Note: The figures in this sub-section were generated by the 5-energy-budget-plant.R script.
The model of canopy temperature is taken from Stanghellini (1987 ,eq. 3.5):
with
plant and indoors climate variables
physical variables
physical constants and approximations
The saturated vapour pressure
It increases with temperature, as seen in the figure:

The slope
The slope is increasing with temperature too, as seen in the figure:

The internal leaf (stomatal) resistance against water vapour
with species-specific coefficients that we here set to
Here is an example, how

The external leaf (boundary layer) resistance to water vapour
where
This figure shows the behaviour of

Both
Note: Due to all the uncertainties, we use a fixed value in the model defaulting to
Everything above taken together, we get the following linear response of plant temperature

Clearly, a high air humidity works against plant transpiration and leads to a higher leaf temperature, even above the ambient temperature of the greenhouse: Relatively cool leaves are a sign of a sound microclimate.
Note: The figures in this sub-section were generated by the 5-energy-budget-plant.R script.
The model of canopy transpiration rate
with symbols defined as for eq.

Obviously, transpiration is larger in a drier climate and it increases with the absorbed radiation. Note that leaf temperature (previous figure) too increased with absorbed radiation. This means that the increase in transpiration with increased absorbed radiation was not sufficient to keep leaf temperature constant; that would have acquired an even higher transpiration.
The phase change from water (in the plant) to water vapour (in the greenhouse air) causes an increase in the latent heat carried by the air. This heat, which is equal to

The 1:1 dashed line has been added to highlight the balance between the radiation absorbed by the canopy and the latent heat lost from the canopy. Below the line the canopy is warmer than the air, above the line the canopy is cooler than the air. Compare this with the figure of canopy temperature above. At a relative humidity of 90%, both the blue lines cross the respective reference lines at ca.
The convective model of heat transfer does not match the complex physiology and physics of the canopy layer; all heat fluxes are taken care of by eqs.
Heat pipes are installed to heat the greenhouse by convection and long-wave radiation. The transmissivity of the heat pipe layer is
The drop in temperature (
where
The transit time
As an example, a pipe with an inner diameter of 30 mm installed at a density of 2 m/m2 in a greenhouse area of 10 000 m2 holds the volume,
which at a flow rate of
The energy lost from the heat pipe
where
As an example, we set heat-pipes.R script):

Heat pipe energy is emitted as a combination of radiant and convective heat. We denote the proportion of long-wave radiation
The other part is conveyed to the greenhouse air. Since convective heat is defined relative to the layers (eq.
Since the volume above and below the heat pipes is the same, i.e. the greenhouse air, we let
A floor made of concrete has typical values
Soil is not treated as a layer in the model but as a volume below the floor layer (see Volumes and Layers). Anyway, the model of soil temperature is naturally presented here.
Soil is defined only vaguely by the model. As a volume it is endless in reality, and it has got not a single temperature but a gradient of temperatures stretching downwards under the greenhouse and inwards from the base of the walls. Considering the complexity of vertical and horizontal gradients of soil temperature, a simple, generic model is called for. Consequently, we set soil temperature at time
All setpoints are defined to be in effect for a certain time interval, both in terms of calendar period and daily time interval. Thus setpoints may change during the year and during the day.
Some setpoints can take on a range of values depending on an input variable. Here are two examples:

Such proportional setpoints are defined by their range (
Proportional setpoints are written in the notation:
The two examples above are, respectively,
Hence, a proportional setpoint involves the definition of four setpoints:
the
the
the setpoint value
the setpoint value
If the band width is set to zero
The humidity setpoint
This boxscript sets the humidity threshold rhMax to 80 from May to August and otherwise to 90. The proportional band is always 5:
xxxxxxxxxx241Box setpoints {2Box rhMax {3PrioritySignal threshold {4DateTimeSignal {5.beginDate = 1/56.endDate = 31/87.signalInside = 808}9DateTimeSignal {10.beginDate = 1/111.endDate = 31/1212.signalInside = 9013}14}15PrioritySignal band {16DateTimeSignal {17.beginDate = 1/118.endDate = 31/1219.signalInside = 520}21}22}23:24}
The rhMac/threshold box is a PrioritySignal box, which means that it will check the boxes inside one by one and pick the first one that should be activated according to the current data (maintained by the calendar box; see Boxscript example with calendar). Here as elsewhere, a lonely : denotes left-out lines.
The heating setpoint
the base heating setpoint
the heating offset at high humidity
A simple boxscript goes to specify this:
xxxxxxxxxx241Box setpoints {2:3Box heating {4PrioritySignal base {5DateTimeSignal {6.beginDate = 1/47.endDate = 30/98.signalInside = 209}10DateTimeSignal {11.beginDate = 1/112.endDate = 31/1213.signalInside = 2214}15}16PrioritySignal humidityOffset {17DateTimeSignal {18.beginDate = 1/119.endDate = 31/1220.signalInside = 221}22}23}24}
Here setpoints/heating/base[value] is 20 from April to September and otherwise 22. The setpoints/heating/huimityOffset[value] is 2 always. The heating setpoint
where
In average climate control, the base heating setpoint
This functionality has not yet been implemented.
The ventilation setpoint
the heating setpoint
the base ventilation offset
the ventilation offset at high humidity
In the boxscript, the humidity offset is given a negative value (here -1.5) to ease the handling of setpoints by the ventilation controller:
xxxxxxxxxx201Box setpoints {2:3Box ventilation {4PrioritySignal baseOffset {5DateTimeSignal {6.beginDate = 1/17.endDate = 31/128.signalInside = 29}10}11PrioritySignal humidityOffset {12DateTimeSignal {13.beginDate = 1/114.endDate = 31/1215.signalInside = -1.516}17}18}19}20
The ventilation setpoint
where
At high indoors humidity
In this boxscript, the ventilation crack has been set to 0.5. The realised ventilation crack is determined by the ventilation crack controller, governed by the humidity setpoint but also taking into account the ventilationCrack/temperature setpoint. In this example, the ventilation crack will keep its full value (
xxxxxxxxxx291Box setpoints {2:3Box ventilationCrack {4PrioritySignal size {5DateTimeSignal {6.beginDate = 1/17.endDate = 31/128.signalInside = 0.59}10}11Box temperature {12PrioritySignal threshold {13DateTimeSignal {14.beginDate = 1/115.endDate = 31/1216.signalInside = -517}18}19PrioritySignal band {20DateTimeSignal {21.beginDate = 1/122.endDate = 31/1223.signalInside = 324}25}26}27}28}29
A screen crack setpoint would be defined to ensure that screens would not block the free passage of air through the vents, when ventilation were necessary. However, the ventilation model is not detailed enough to correct for the influence of screens on the effectiveness of the vents. Hence, the model does not include a screen crack setpoint.
Growth lights are arranged into banks, which each follow their own logic; growth lights in a bank are switched on/off together. A bank can be operating in any of three modes designated by a code (0, 1 or 10):
0: growth light is off
1: growth light is on only when additional light is needed
10: growth light is on
The mode is itself a setpoint. Hence, you can change any aspect of the growth light logic through time.
In the following example there are two banks of setpoints, named bank1 and bank2. Banks can be named freely but the same names must be used in growth light controllers and actuators too; furthermore, a bank most hold a child box called mode.
xxxxxxxxxx601Box setpoints {2:3Box growthLights {4Box bank1 {5PrioritySignal mode {6DateTimeSignal {7.beginDate = 01/118.endDate = 30/119.beginTime = 06:00:0010.endTime = 10:00:0011.signalInside = 1012}13DateTimeSignal {14.beginDate = 01/1015.endDate = 31/1216.beginTime = 06:00:0017.endTime = 18:00:0018.signalInside = 119}20DateTimeSignal {21.beginDate = 1/1022.endDate = 31/1223.signalInside = 024}25}26Box thresholds {27PrioritySignal low {28DateTimeSignal {29.beginDate = 1/130.endDate = 31/1231.signalInside = 4032}33}34PrioritySignal high {35DateTimeSignal {36.beginDate = 1/137.endDate = 31/1238.signalInside = 60039}40}41}42}43Box bank2 {44PrioritySignal mode {45DateTimeSignal {46.beginDate = 1/1047.endDate = 31/0248.beginTime = 04:0049.endTime = 08:0050.signalInside = 1051}52DateTimeSignal {53.beginDate = 1/154.endDate = 31/1255.signalInside = 056}57}58}59}60}
The outcome of these setpoints is for bank1:
In November growth lights are on between 6 and 10 a.m.
In October and December growth lights are on when outdoors light is less than 40 W/m2, except when outdoors light is above 600 W/m2.
All other months growth lights are off.
For bank2:
From October to February growth lights are on between 4 and 8 a.m.
All other months growth lights are off.
Strictly speaking, it is decided by the growth light controller (here the controllers/growthLights/bank1 controller) which variable the thresholds refer to.
The glass may be chalked (whitened) to lessen radiative transmission. The setpoint is a number between 0 and 1 allowing for varying strengths of whitening. The actual strength is set by the chalk controller, which makes it possible to reduce whitening strength with time or due to events such as heavy rainfall. The actual, radiative effect of chalking is determined by the chalk actuator.
The example whitening is fully on from 1 March to 15 April; otherwise it is off:
xxxxxxxxxx151Box setpoints {2:3PrioritySignal chalk {4DateTimeSignal {5.beginDate = 1/36.endDate = 15/47.signalInside = 18}9DateTimeSignal {10.beginDate = 1/111.endDate = 31/1212.signalInside = 013}14}15}
Screen setpoints provide setpoint values used by the screen controllers. You should give the setpoint boxes names that will make it easy for you to recall their relations to the screen layers defined in the screen house construction. Please refer to the Boxscript example with cover and screens) which we continue in the boxscript further down.
In general, energy screens will need a threshold below which the curtain should drawn (e.g., in response to outdoors radiation), whereas shade and blackout screens need a threshold above which they will be drawn. Screen setpoints are usually proportional setpoints and thus need a proportional band in addition to the threshold. Both the threshold and the proportional band can be set up with different values for different periods of the year and the day.
In this example, the setpoints are divided into three groups, each held inside one box: energy, shade and blackout. A value is set for a certain period by a DateTimeSignal box. For instance, the shade/threshold box holds three DateTimeSignal boxes (lines 20-37). The shade/threshold box itself is a PrioritySignal box, which means that it will check the boxes inside one by one and pick the first one that should be activated according to the current data and time (maintained by the calendar box; see Boxscript example with calendar). The dates beginDate and endDate are inclusive. In this case, the result will be that the output port setpoints/shade/threshold[value] (to spell out the unique path identifying this port) will take on the value 300 in December and January, 400 from 1 February until 15 March and 500 from 16 March until 30 November. Meanwhile, the proportional band at setpoints/shade/band[value] will always be 50.
For easier reading, you can follow my example and always define a PrioritySignal box even though it holds only one DateTimeSignal, which is then a given choice. If none of the boxes held by PrioritySignal matches the current date and time, it will sets its value to zero which is rarely wanted. Hence, it is best always with to have a final DateTimeSignal box that spans the whole year.
The blackout setpoint (lines 46-70) causes the screen to be on from 1 April to 15 June every night from 4 a.m., when outdoor light is above a threshold value of 2. Outside this period of the day and of the year, the threshold value is 9999, i.e. the screen will be off since light (if its in W/m2) will never surpass this value.
xxxxxxxxxx711Box setpoints {2:3Box screens {4Box energy {5PrioritySignal threshold {6DateTimeSignal {7.beginDate = 1/18.endDate = 31/129.signalInside = 510}11}12PrioritySignal band {13DateTimeSignal {14.beginDate = 1/115.endDate = 31/1216.signalInside = 017}18}19}20Box shade {21PrioritySignal threshold {22DateTimeSignal {23.beginDate = 1/1224.endDate = 31/125.signalInside = 30026}27DateTimeSignal {28.beginDate = 1/129.endDate = 15/330.signalInside = 40031}32DateTimeSignal {33.beginDate = 1/134.endDate = 31/1235.signalInside = 50036}37}38PrioritySignal band {39DateTimeSignal {40.beginDate = 1/141.endDate = 31/1242.signalInside = 5043}44}45}46Box blackout {47PrioritySignal threshold {48DateTimeSignal {49.beginDate = 1/450.endDate = 15/651.beginTime = 04:0052.endTime = 12:0053.signalInside = 254.signalOutside = 999955}56DateTimeSignal {57.beginDate = 1/158.endDate = 31/1259.signalInside = 999960}61}62PrioritySignal band {63DateTimeSignal {64.beginDate = 1/165.endDate = 31/1266.signalInside = 067}68}69}70}71}
The CO2 setpoint sets the desired minimum CO2 concentration (ppm). As an example, the boxscript below setpoint sets CO2 at 1200 ppm in the summer and at 900 ppm for the rest of the year:
xxxxxxxxxx331Box setpoints {2:3Box co2 {4PrioritySignal concentration {5DateTimeSignal {6.beginDate = 15/67.endDate = 31/088.signalInside = 12009}10DateTimeSignal {11.beginDate = 1/112.endDate = 31/1213.signalInside = 90014}15}16Box ventilation {17PrioritySignal threshold {18DateTimeSignal {19.beginDate = 1/120.endDate = 31/1221.signalInside = 0.222}23}24PrioritySignal band {25DateTimeSignal {26.beginDate = 1/127.endDate = 31/1228.signalInside = 0.129}30}31}32}33}
At high ventilation rates, CO2 enrichment is a waste. In the boxscript above, the limit has been set at 0.2 h0.1 h
The CO2 setpoint is passed on to the CO2 controller, while the ventilation-dependent limitation is applied directly by the CO2 actuator.
Controllers add further to the logic imposed by setpoints.
The heating controller takes the base heating set point and adds the humidity offset for heating. Both values are set by the heating setpoint.
In the boxscript below, controllers/heating is a Sum box which adds the base value and the humidity offset (the pipe | operator signifies a union of the matches provide by the two paths setpoints/heating/base[value] and ./humidityOffset[value]).
The offset is calculated by the child box (referred to by a leading period, i.e. ./humidityOffset[value]), which again is a ProportionalSignal governed by the humidity setpoint and the current indoors humidity indoors[rh]. Note how the maximum possible offset is grabbed from the setpoint setpoints/heating/humidityOffset[value]. The offset is increasing with humidity through the threshold band.
xxxxxxxxxx131Box controllers {2:3Sum heating {4.values = setpoints/heating/base[value] | ./humidityOffset[value]5ProportionalSignal humidityOffset {6.input = indoors[rh]7.threshold = setpoints/rhMax/threshold[value]8.thresholdBand = setpoints/rhMax/band[value]9.maxSignal = setpoints/heating/humidityOffset[value]10.increasingSignal = TRUE11}12}13}
The ventilation controller works very much like the heating controller, except it adds up three values (cf.
xxxxxxxxxx151Box controllers {2:3Sum ventilation {4.values = controller/heating[value] |5setpoints/ventilation/baseOffset[value] |6./humidityOffset[value]7ProportionalSignal humidityOffset {8.input = indoors[rh]9.threshold = setpoints/rhMax/threshold[value]10.thresholdBand = setpoints/rhMax/band[value]11.maxSignal = setpoints/ventilation/humidityOffset[value]12.increasingSignal = TRUE13}14}15}
The three values are taken from three different sources: the heating controller, the ventilation setpoint and the realised humidity offset computed by its own child box. The ventilation actuator must take both the ventilation controller and the ventilation crack controller into account when determining the actual ventilation rate.
The ventilationCrack controller first restricts the size of the crack by the temperature limitation imposed by outdoors temperature (lines 9-15) (in BoxScript, children are updated before parents). This crack value ./temperatureLimited[value] is then moderated further by way of the humidity setpoint to arrive at the final crack controllers/ventilationCrack[value].
xxxxxxxxxx171Box controllers {2:3ProportionalSignal ventilationCrack {4.input = indoors[rh]5.threshold = setpoints/rhMax/threshold[value]6.thresholdBand = setpoints/rhMax/band[value]7.maxSignal = ./temperatureLimited[value]8.increasingSignal = TRUE9ProportionalSignal temperatureLimited {10.input = outdoors[temperature]11.threshold = setpoints/ventilationCrack/temperature/threshold[value]12.thresholdBand = setpoints/ventilationCrack/temperature/band[value]13.maxSignal = setpoints/ventilationCrack/size[value]14.increasingSignal = TRUE15}16}17}
There may be several growth light controllers, one for each bank of growth lights. A growth light controller switches the growth lights in the bank on/off according to the growth light setpoints. To continue the setpoint example, we can define the following two controllers:
xxxxxxxxxx161Controllers {2:3Box growthLights {4GrowthLightController bank1 {5.mode = setpoints/growthLights/bank1/mode[value]6.thresholdValue = outdoors[radiation]7.thresholdLow = setpoints/growthLights/bank1/thresholds/low[value]8.thresholdHigh = setpoints/growthLights/bank1/thresholds/high[value]9.minPeriodOn = 5.10}11GrowthLightController bank2 {12.mode = setpoints/growthLights/bank2/mode[value]13.minPeriodOn = 30.14}15}16}
Due to the complicated control logic, a dedicated GrowthLightController is needed for each bank. The bank1 controller refers to the bank1 setpoints (lines 5, 7 and 8) and likewise for bank2 (line 12). Only bank1 needs the inputs thresholdValue, thresholdLow and thresholdHigh; bank2 is not threshold-controlled. The optional minPeriodOn can be set to obtain a certain minimum periods (in minutes) for the lights being switched on.
The CO2 controller is a PID controller which controls the CO2 injection system to regulate the CO2 towards the CO2 setpoint.
A PidController box has three parameters:
Kprop for proportional (P) control
Kint for integral (I) control
Kderiv for derivate (D) control
These are used to steer the sensedValue towards the desiredValue. This boxscript provides an example in which only proportional control Kprop is applied:
xxxxxxxxxx111Box controllers {2:3Box co2 {4&change = ./controller[controlVariable]5PidController controller {6.sensedValue = indoors/co2[value]7.desiredValue = setpoints/co2[value]8.Kprop = 0.059}10}11}
PidController produces the controlVariable output which tends towards zero, when the P+I+D terms tend towards a zero sum. Here, it used as an indicator how much the CO2 injection rate should change (line 4). The co2[change] output is used as an input by the CO2 actuator.
The screen controllers use the screen setpoints together with inputs provided, e.g., from the outdoors box to compute desired screen states between 0 (fully off) to 1 (fully on). As mentioned earlier, there is no screen crack setpoint to take into account.
With the definitions given in the boxscript example with screen setpoints, we could write the following three controllers, which all responds to outdoors radiation (W/m2) provided by outdoors[radiation]:
xxxxxxxxxx261Box controllers {2:3Box screens {4ProportionalSignal energy {5.input = outdoors[radiation]6.threshold = setpoints/screens/energy/threshold[value]7.thresholdBand = setpoints/screens/energy/band[value]8.maxSignal = 19.increasingSignal = FALSE10}11ProportionalSignal shade {12.input = outdoors[radiation]13.threshold = setpoints/screens/shade/threshold[value]14.thresholdBand = setpoints/screens/shade/band[value]15.maxSignal = 116.increasingSignal = TRUE17}18ProportionalSignal blackout {19.input = outdoors[radiation]20.threshold = setpoints/screens/blackout/threshold[value]21.thresholdBand = setpoints/screens/blackout/band[value]22.maxSignal = 123.increasingSignal = TRUE24}25}26}
Note how the increasingSignal input tells whether the signal computed by a ProportionalSignal box is increasing or decreasing in response to the input. There is also a minSignal input but this defaults to 0, which is just what we want.
All boxes of the Signal classes (ProportionalSignal, PrioritySignal, etc.) provide their about under two equivalent names, value and signal.
The chalk controller may provide mechanisms to modulate the whitening strength set by the chalk setpoint. Most simply it just passes on the setpoint:
xxxxxxxxxx61Box controllers {2:3Box chalk {4&value = controllers/chalk[value]5}6}
The chalk actuator retrieves the current whitening strength from /controllers/chalk[value].
Each bank of growth lights is controlled by a growth light controller for which there exists a growth light actuator with the same name (e.g., bank1, bank2)
A growth light actuator is described by the parameters:
installed lamp power
optimal PAR efficiency
efficiency correction
proportion of emitted radiation that is long-waved
ballast
The efficiency of lamps will degrade with their age. The product
See the Growth light layer section for details on growth light function. Then outputs of all sets of growth lights are added and considered one layer.
xxxxxxxxxx211Box actuators2:3Box growthLights {4ActuatorGrowthLight bank1 {5.isOn = controllers/growthLights/bank1[isOn]6.power = 1007.parPhotonCoef = 2.58.efficiency = 1.09.propLw = 0.110.ballast = 011}12ActuatorGrowthLight bank2 {13.isOn = controllers/growthLights/bank2[isOn]14.power = 8015.parPhotonCoef = 1.616.efficiency = 0.817.propLw = 0.318.ballast = 1019}20}21
Each screen actuator is governed by a controller. It has a lagPeriod input, which is the time taken (in minutes) to drag the screen all the way from position 0 to 1 (or from 1 to 0). If the lag period is much smaller than the simulation time step, it is better to set it to zero to avoid unrealistic delays in effectuating screen settings.
To continue the boxscript example with screen controllers, we could write
xxxxxxxxxx171Box actuators {2:3Box screens {4ActuatorScreen energy {5.position = controllers/screens/energy[value]6.lagPeriod = 107}8ActuatorScreen shade {9.position = controllers/screens/shade[value]10.lagPeriod = 1011}12ActuatorScreen blackout {13.position = controllers/screens/blackout[value]14.lagPeriod = 1015}16}17}
There can be several sets of of heat pipes installed. Each set of heat pipes is described by the parameters:
water volume in pipe
water flow rate
calibration parameters
proportion of heat emitted is long-waved radiation
See the Heat pipe layer section for details on heat pipe function. Then outputs of all sets of heat pipes are added and considered one layer.
The actual pipe inlet temperature
Vents are characterised by their width and length and the number of vents installed. If vents of different dimensions are installed, they are specified as different sets. The total area of vents
The actual ventilation rate
The CO2 actuator injects CO2 at a rate of 60:
xxxxxxxxxx181Box actuators {2:3Box co2 {4&injectionRate = ./injectionRate[value]5Accumulator injectionRate {6.change = controllers/co2/injectionRate[change]7.minValue = 08.maxValue = ./injectionRate[value]9ProportionalSignal injectionrate {10.input = actuators/ventilation[value]11.threshold = setpoints/co2/ventilation/threshold[value]12.thresholdBand = setpoints/co2/ventilation/band[value]13.maxSignal = 6014.increasingSignal = FALSE15}16}17}18}
When deciphering this boxscript, remember that boxscripts are interpreted child-first. Hence injectionRate in lines 9-15 comes first. Here, the maximum injection rate is adjusted for the current ventilation rate, which might limit it below the set maximum of 60 (line 13). This value is taken by the parent box (lines 5-16) as an input (line 8) to set the maximum ventilation rate arrived at by PID control. Accumulator is a box that in every time step adds the change input (line 6) to its current value. The value can, however, never exceed the bounds set by minValue and maxValue (lines 7-8). The change input was computed by the CO2 controller by PID control. The resulting valueis finally set as the injectionRate in line 4. Thus the CO2 budget model can retrieve the current CO2 injection rate from the port actuators/co2[injectionRate].
The current strength of whitening (
As an example, if the cover has the properties
Here is a boxscript example:
xxxxxxxxxx81Box actuators {2:3ActuatorChalk chalk {4.state = controllers/chalk[value]5.swReflectivity = 0.26.lwReflectivity = 0.17}8}
We build the energy budget by adding the processes of heat exchange one by one. The step-wise construction is reflected in R scripts that progressively includes more and more of the energy budget.
Radiation enters the model as layers may emit radiation downwards from the bottom
The primary emission plus the transmitted and reflected radiation defines the net flows of radiation downwards
| Layer | Temperature | Short-waved radiation | Long-waved radiation |
|---|---|---|---|
| Sky | driving variable | driving variable | |
| Cover | state variable, | 0 | |
| Screen | state variable, | 0 | |
| Growth light | n.a. | state variable, | state variable, |
| Plant canopy | state variable, | 0 | |
| Heat pipe | state variable, | 0 | state variable, |
| Floor | state variable, | 0 |
For the sky both its temperature and short-wave emission are driving variables (usually read from a weather log file). Its downward long-wave emission is calculated from its temperature.
For cover, screen and floor layers, temperature is updated according to the heat balance
where
For growth light, temperature is not tracked. A dedicated sub-model, denoted as a function with numerous inputs
As radiation is emitted, absorbed, reflected and transmitted by the layers, a net radiation flux will result downwards and upwards for each layer
The net radiation fluxes throughout the stack of layers are resolved by resolving them two layers at a time. Consider layer

Our first aim is to find out, how much of the downwards radiation from the upper layer
However, a fraction of the light will be reflected by the upperside of the lower layer (
and so forth as photons keep bouncing between the two layers,
Since the reflectivies are less than one, the infinite series will converge as
and we get the amount absorbed by the lower layer
The net transmission through the lower layer
On every bounce of the radiation, fractions will be lost to absorption by and transmission through the upper layer. Thus the calculations for the underside of the upper layer are the same, except that the we start out with what's first reflected upwards from the lower layer (
One consequence of these reflections is that part of the downwards radiation from the upper layer
Let's check that we have now accounted for the fate all radiation downwards from layer
Thus we have accounted for it all.
Having accounted for the fate of the downwards radiation from layer
After we have finished the distribution of downwards radiation, we repeat the procedure this time going from the bottom to the top following the upwards radiation,
We repeat the calculations downwards-upwards, on each pass accumulating in each layer the radiation absorbed from above
The PAR budget is resolved just as the short-wave budget above. However, PAR is not part of the energy budget. Its only role is to provide energy for photosynthesis in the canopy layer. It needs a special treatment because the emission of PAR
The 1-energy-budget-sw.R script demonstrates the calculations. Here the light layer emits 100 W/m2 downwards (or 100 μmol/m2/s; the calculations are the exact same). The zero emission of short-wave radiation from the sky indicates a night situation. Greek letters are represented by their Latin equivalent and primes have been replaced by underscores:
xxxxxxxxxx81Layer a r t a_ r_ t_ E E_ F F_ A A_21 Sky 1.00 0.00 0.00 1.00 0.00 0.00 0 0 0 0 0 032 Glass 0.03 0.08 0.89 0.03 0.08 0.89 0 0 0 0 0 043 Screen 0.10 0.60 0.30 0.10 0.60 0.30 0 0 0 0 0 054 Light 0.00 0.00 1.00 0.00 0.00 1.00 100 0 100 0 0 065 Plant 0.71 0.05 0.24 0.71 0.05 0.24 0 0 0 0 0 076 Heating 0.00 0.00 1.00 0.00 0.00 1.00 0 0 0 0 0 087 Floor 0.60 0.40 0.00 1.00 0.00 0.00 0 0 0 0 0 0
The radiative parameters for the plant layer was computed for
After the first distribution of radiation downwards, we have
xxxxxxxxxx81Layer a r t a_ r_ t_ E E_ F F_ A A_21 Sky 1.00 0.00 0.00 1.00 0.00 0.00 0 0 0 0.0 0.0 032 Glass 0.03 0.08 0.89 0.03 0.08 0.89 0 0 0 0.0 0.0 043 Screen 0.10 0.60 0.30 0.10 0.60 0.30 0 0 0 0.0 0.0 054 Light 0.00 0.00 1.00 0.00 0.00 1.00 100 0 0 5.0 0.0 065 Plant 0.71 0.05 0.24 0.71 0.05 0.24 0 0 0 0.0 71.0 076 Heating 0.00 0.00 1.00 0.00 0.00 1.00 0 0 0 9.6 0.0 087 Floor 0.60 0.40 0.00 1.00 0.00 0.00 0 0 0 0.0 14.4 0
We can see that
xxxxxxxxxx81Layer a r t a_ r_ t_ E E_ F F_ A A_21 Sky 1.00 0.00 0.00 1.00 0.00 0.00 0 0 0.0 0 0.0 2.032 Glass 0.03 0.08 0.89 0.03 0.08 0.89 0 0 0.0 0 0.0 0.143 Screen 0.10 0.60 0.30 0.10 0.60 0.30 0 0 0.1 0 0.0 0.754 Light 0.00 0.00 1.00 0.00 0.00 1.00 100 0 4.4 0 0.0 0.065 Plant 0.71 0.05 0.24 0.71 0.05 0.24 0 0 0.0 0 71.0 6.876 Heating 0.00 0.00 1.00 0.00 0.00 1.00 0 0 0.5 0 0.0 0.087 Floor 0.60 0.40 0.00 1.00 0.00 0.00 0 0 0.0 0 14.4 0.0
This led to a total of A_ column) being absorbed on the underside of various layers (sky, glass, screen, plant). Meanwhile, reflection downwards led to the remaining radiation of F column) hitting som layers (screen, light, heating) from above.
If we set the precision, so that the calculations down and up will be repeated until
xxxxxxxxxx81Layer a r t a_ r_ t_ E E_ F F_ A A_21 Sky 1.00 0.00 0.00 1.00 0.00 0.00 0 0 0 0 0.0 2.232 Glass 0.03 0.08 0.89 0.03 0.08 0.89 0 0 0 0 0.0 0.143 Screen 0.10 0.60 0.30 0.10 0.60 0.30 0 0 0 0 0.0 0.854 Light 0.00 0.00 1.00 0.00 0.00 1.00 100 0 0 0 0.0 0.065 Plant 0.71 0.05 0.24 0.71 0.05 0.24 0 0 0 0 74.3 7.376 Heating 0.00 0.00 1.00 0.00 0.00 1.00 0 0 0 0 0.0 0.087 Floor 0.60 0.40 0.00 1.00 0.00 0.00 0 0 0 0 15.4 0.0
Thus
The same algorithm as for short-wave radiation above is used to resolve the fate of long-wave radiation, i.e. its distributed among the layers. However, the absorption of radiation (both short-wave and long-wave radiation) will cause a change in the temperature of the layer
Note that the distribution of short-wave radiation remains constant because it is temperature-independent. Only the long-wave emission of the layers will change and converge, as a solution is found in which all temperatures are stable and by that, the heat exchange by radiation is in a steady state.
The 2-energy-budget-lw.R script demonstrates the calculations, which follow the same logic as for short-wave radiation above but with some extra parameters and calculation steps.
Here is the initial set-up. Columns T and C have been added to hold temperature and heat capacity. Incidentally,
xxxxxxxxxx81Layer a r t a_ r_ t_ T C E E_ A A_21 Sky 0.00 0.00 1.0 1.00 0.00 0.0 -10 Inf 271.9 0.0 0.0 2.232 Glass 0.88 0.12 0.0 0.88 0.12 0.0 15 8400 344.0 344.0 0.0 0.143 Screen 0.07 0.93 0.0 0.57 0.43 0.0 18 2280 232.3 28.5 0.0 0.854 Light 0.00 0.00 1.0 0.00 0.00 1.0 NA Inf 15.0 15.0 0.0 0.065 Plant 0.79 0.01 0.2 0.79 0.01 0.2 24 Inf 349.3 349.3 74.3 7.376 Heating 0.00 0.00 1.0 0.00 0.00 1.0 NA Inf 75.0 75.0 0.0 0.087 Floor 0.60 0.40 0.0 0.00 0.00 1.0 12 42000 0.0 224.9 15.4 0.0
We have transferred the absorbed short-wave radiation from the example above (columns A and A_). The emissions (E and E_) have been set according to layer temperatures and emissivities, applying Stefan-Boltzmann's Law (eq.
The radiative parameters for the plant layer was computed for
It worth noting that screens may have an asymmetric emissivity for long-wave radiation (
The temperature of layers that have been given an infinite heat capacity, does not change in temperature by the absorbed radiation. However, the plant temperature is kept fixed in this budget for now, until we have included the full plant canopy sub-model (see canopy temperature), which among other things calculates leaf temperature.
We use the same algorithm as for short-wave radiation to distribute the flows of long-wave radiation. We arrive at this solution of the long-wave plus short-wave radiation budget:
xxxxxxxxxx81Layer a r t a_ r_ t_ T C E E_ A A_21 Sky 0.00 0.00 1.0 1.00 0.00 0.0 -10 Inf 271.9 0.0 0.0 378.832 Glass 0.88 0.12 0.0 0.88 0.12 0.0 15 8400 344.0 344.0 239.3 345.243 Screen 0.07 0.93 0.0 0.57 0.43 0.0 18 2280 232.3 28.5 27.4 268.854 Light 0.00 0.00 1.0 0.00 0.00 1.0 NA Inf 15.0 15.0 0.0 0.065 Plant 0.79 0.01 0.2 0.79 0.01 0.2 24 Inf 349.3 349.3 429.4 408.376 Heating 0.00 0.00 1.0 0.00 0.00 1.0 NA Inf 75.0 75.0 0.0 0.087 Floor 0.60 0.40 0.0 0.00 0.00 1.0 12 42000 0.0 224.9 326.9 0.0
We left step 1 with A and A_) and E and E_). After step 2 the long-wave emission has been added, and we have
The net absorbed radiation for any layer
How much of a change in glass temperature this will cause, depends on the time step. Let's say the simulation time step for the whole model is
In general, we should set
where
We update the temperature of screen and floor in the same manner and get
xxxxxxxxxx81Layer a r t a_ r_ t_ T C E E_ A A_21 Sky 0.00 0.00 1.0 1.00 0.00 0.0 -10.0 Inf 271.9 0.0 0 032 Glass 0.88 0.12 0.0 0.88 0.12 0.0 14.6 8400 344.0 344.0 0 043 Screen 0.07 0.93 0.0 0.57 0.43 0.0 18.5 2280 232.3 28.5 0 054 Light 0.00 0.00 1.0 0.00 0.00 1.0 NA Inf 15.0 15.0 0 065 Plant 0.79 0.01 0.2 0.79 0.01 0.2 24.0 Inf 349.3 349.3 0 076 Heating 0.00 0.00 1.0 0.00 0.00 1.0 NA Inf 75.0 75.0 0 087 Floor 0.60 0.40 0.0 0.00 0.00 1.0 12.1 42000 0.0 224.9 0 0
In summary, the glass was cooled by 0.37 K, while screen and floor was heated by 0.48 K and 0.08 K, respectively, during the 30 s time step. The net absorption by the plant canopy is ignored for now. The absorption columns A and A_ have been set to zero too reflect that the absorbed energy has been transformed to heat.
Since the temperature of glass, screen and floor has changed, we must update their long_wave emission in columns E and E_:
xxxxxxxxxx81Layer a r t a_ r_ t_ T C E E_ A A_21 Sky 0.00 0.00 1.0 1.00 0.00 0.0 -10.0 Inf 271.9 0.0 0 032 Glass 0.88 0.12 0.0 0.88 0.12 0.0 14.6 8400 342.2 342.2 0 043 Screen 0.07 0.93 0.0 0.57 0.43 0.0 18.5 2280 233.7 28.7 0 054 Light 0.00 0.00 1.0 0.00 0.00 1.0 NA Inf 15.0 15.0 0 065 Plant 0.79 0.01 0.2 0.79 0.01 0.2 24.0 Inf 349.3 349.3 0 076 Heating 0.00 0.00 1.0 0.00 0.00 1.0 NA Inf 75.0 75.0 0 087 Floor 0.60 0.40 0.0 0.00 0.00 1.0 12.1 42000 0.0 225.2 0 0
The short-wave absorption is unaltered and is once again (as in step 1) entered into columns A and A_. Likewise, the long-wave radiation of light and heating remain unchanged in columns E and E_:
xxxxxxxxxx81Layer a r t a_ r_ t_ T C E E_ A A_21 Sky 0.00 0.00 1.0 1.00 0.00 0.0 -10.0 Inf 271.9 0.0 0.0 2.232 Glass 0.88 0.12 0.0 0.88 0.12 0.0 14.6 8400 342.2 342.2 0.0 0.143 Screen 0.07 0.93 0.0 0.57 0.43 0.0 18.5 2280 233.7 28.7 0.0 0.854 Light 0.00 0.00 1.0 0.00 0.00 1.0 NA Inf 15.0 15.0 0.0 0.065 Plant 0.79 0.01 0.2 0.79 0.01 0.2 24.0 Inf 349.3 349.3 74.3 7.376 Heating 0.00 0.00 1.0 0.00 0.00 1.0 NA Inf 75.0 75.0 0.0 0.087 Floor 0.60 0.40 0.0 0.00 0.00 1.0 12.1 42000 0.0 225.2 15.4 0.0
After step 5 we return to step 2 and loop through the calculations, step 2 to 5, for a total of
xxxxxxxxxx81Layer a r t a_ r_ t_ T C E E_ A A_21 Sky 0.00 0.00 1.0 1.00 0.00 0.0 -10.0 Inf 271.9 0.0 0 032 Glass 0.88 0.12 0.0 0.88 0.12 0.0 12.9 8400 335.6 335.6 0 043 Screen 0.07 0.93 0.0 0.57 0.43 0.0 20.5 2280 239.1 29.4 0 054 Light 0.00 0.00 1.0 0.00 0.00 1.0 NA Inf 15.0 15.0 0 065 Plant 0.79 0.01 0.2 0.79 0.01 0.2 24.0 Inf 349.3 349.3 0 076 Heating 0.00 0.00 1.0 0.00 0.00 1.0 NA Inf 75.0 75.0 0 087 Floor 0.60 0.40 0.0 0.00 0.00 1.0 12.4 42000 0.0 226.1 0 0
The total net absorption for any layer
where we for convenience have left out the emission of short-wave radiation, which amounts to
The energy accumulated by the sky and plant layers were
Noting that the light and heating layers absorb no radiation, we get
We can now calculate the energy balance of the whole system,
This can be compared against the total energy put into the system, namely the
which balances the whole budget to zero and thereby verifies the precision of our calculations.
Unlike the exchange of radiation, which occurs between layers, convective heat transfer occurs between a layer and its surrounding volume of air. The cover exchanges heat with the outdoors air on the outer surface and the inside air on the inner surface. The floor exchanges convective heat with the indoors air. All other layers exchange convective heat with the indoors air on both upper and lower surfaces. The floor in addition exchanges conductive heat with the outdoors soil.
All convective/conductive heat transfers are defined by the U-value of the layer (eq.
We will keep track of the convective/conductive heat absorbed by each volume
where
The convective/conductive heat transfer between layers and volumnes is added to the short-wave and long-wave radiation budget, as demonstrated in the 3-energy-budget-convection.R script.
We have added U and U_) and heat absorbed by convection/conduction H and H_) to the layer budget. In addition, we need a separate budget for the three volumes with columns T, C and H representing
xxxxxxxxxx131Layer T C E E_ A A_ U U_ H H_21 Sky -10 Inf 271.9 0.0 0.0 2.2 0.0 0.0 0 032 Glass 15 8400 344.0 344.0 0.0 0.1 6.4 2.8 0 043 Screen 18 2280 232.3 28.5 0.0 0.8 1.2 1.2 0 054 Light NA Inf 15.0 15.0 0.0 0.0 0.0 0.0 -5 -565 Plant 24 Inf 349.3 349.3 74.3 7.3 1.2 1.2 0 076 Heating NA Inf 75.0 75.0 0.0 0.0 0.0 0.0 -50 -5087 Floor 12 42000 0.0 224.9 15.4 0.0 1.2 0.1 0 0910Volume T C H111 Outdoors 10 Inf 0122 Indoors 25 4780 110133 Soil 6 Inf 0
All the functionality of the short-wave (energy-budget-sw.R) and long-wave budgets (energy-budget-lw.R) is kept. The heat convective/conductive heat exchange between layers and volumes can simply be been added.
The initial set-up now includes the convective heat emitted by growth lights and heat pipes. This has been set to
This step only involves the layers and gives the same result as step 2 in the long-wave radiation budget; the E and E_ columns are distributed into the A and A_ columns:
xxxxxxxxxx131Layer T C E E_ A A_ U U_ H H_21 Sky -10 Inf 271.9 0.0 0.0 378.8 0.0 0.0 0 032 Glass 15 8400 344.0 344.0 239.3 345.2 6.4 2.8 0 043 Screen 18 2280 232.3 28.5 27.4 268.8 1.2 1.2 0 054 Light NA Inf 15.0 15.0 0.0 0.0 0.0 0.0 -5 -565 Plant 24 Inf 349.3 349.3 429.4 408.3 1.2 1.2 0 076 Heating NA Inf 75.0 75.0 0.0 0.0 0.0 0.0 -50 -5087 Floor 12 42000 0.0 224.9 326.9 0.0 1.2 0.1 0 0910Volume T C H111 Outdoors 10 Inf 0122 Indoors 25 4780 110133 Soil 6 Inf 0
The convective/conductive heat fluxes are governed by the layer
xxxxxxxxxx131Layer T C E E_ A A_ U U_ H H_21 Sky -10 Inf 271.9 0.0 0.0 378.8 0.0 0.0 0.0 0.032 Glass 15 8400 344.0 344.0 239.3 345.2 6.4 2.8 -32.0 28.043 Screen 18 2280 232.3 28.5 27.4 268.8 1.2 1.2 8.4 8.454 Light NA Inf 15.0 15.0 0.0 0.0 0.0 0.0 -5.0 -5.065 Plant 24 Inf 349.3 349.3 429.4 408.3 1.2 1.2 1.2 1.276 Heating NA Inf 75.0 75.0 0.0 0.0 0.0 0.0 -50.0 -50.087 Floor 12 42000 0.0 224.9 326.9 0.0 1.2 0.1 15.6 -0.6910Volume T C H111 Outdoors 10 Inf 32.0122 Indoors 25 4780 47.2133 Soil 6 Inf 0.6
We can check that all heat fluxes (columns H and H_) add up to zero:
In other words, the layers are giving off heat to all three volumes, most of it to the indoors and the outdoors air. Only little disappears through the well-insulated floor.
This step corresponds to step 3 for in the the long-wave radiation budget. We get the same resulting layer temperatures as before, as the A and A_ columns are converted to temperature changes and added to the T column:
xxxxxxxxxx131Layer T C E E_ A A_ U U_ H H_21 Sky -10.0 Inf 271.9 0.0 0 0 0.0 0.0 0.0 0.032 Glass 14.6 8400 344.0 344.0 0 0 6.4 2.8 -32.0 28.043 Screen 18.5 2280 232.3 28.5 0 0 1.2 1.2 8.4 8.454 Light NA Inf 15.0 15.0 0 0 0.0 0.0 -5.0 -5.065 Plant 24.0 Inf 349.3 349.3 0 0 1.2 1.2 1.2 1.276 Heating NA Inf 75.0 75.0 0 0 0.0 0.0 -50.0 -50.087 Floor 12.1 42000 0.0 224.9 0 0 1.2 0.1 15.6 -0.6910Volume T C H111 Outdoors 10 Inf 32.0122 Indoors 25 4780 47.2133 Soil 6 Inf 0.6
This step is similar to step 4, but now it is the H and H_ columns that are converted to temperature changes and added to the T column. This step involves both the layers and the indoors volume. Of the layers, only the screen layer changed discernably:
xxxxxxxxxx131Layer T C E E_ A A_ U U_ H H_21 Sky -10.0 Inf 271.9 0.0 0 0 0.0 0.0 0 032 Glass 14.6 8400 344.0 344.0 0 0 6.4 2.8 0 043 Screen 18.7 2280 232.3 28.5 0 0 1.2 1.2 0 054 Light NA Inf 15.0 15.0 0 0 0.0 0.0 0 065 Plant 24.0 Inf 349.3 349.3 0 0 1.2 1.2 0 076 Heating NA Inf 75.0 75.0 0 0 0.0 0.0 0 087 Floor 12.1 42000 0.0 224.9 0 0 1.2 0.1 0 0910Volume T C H111 Outdoors 10.0 Inf 0122 Indoors 25.3 4780 0133 Soil 6.0 Inf 0
Since the temperature of glass, screen and floor has changed, we must update their long_wave emission in columns E and E_:
xxxxxxxxxx131Layer T C E E_ A A_ U U_ H H_21 Sky -10.0 Inf 271.9 0.0 0 0 0.0 0.0 0 032 Glass 14.6 8400 342.2 342.2 0 0 6.4 2.8 0 043 Screen 18.7 2280 234.5 28.8 0 0 1.2 1.2 0 054 Light NA Inf 15.0 15.0 0 0 0.0 0.0 0 065 Plant 24.0 Inf 349.3 349.3 0 0 1.2 1.2 0 076 Heating NA Inf 75.0 75.0 0 0 0.0 0.0 0 087 Floor 12.1 42000 0.0 225.2 0 0 1.2 0.1 0 0910Volume T C H111 Outdoors 10.0 Inf 0122 Indoors 25.3 4780 0133 Soil 6.0 Inf 0
The short-wave absorption is unaltered and is entered into columns A and A_, likewise, the heating fluxes in columns H and H_:
xxxxxxxxxx131Layer T C E E_ A A_ U U_ H H_21 Sky -10.0 Inf 271.9 0.0 0.0 2.2 0.0 0.0 0 032 Glass 14.6 8400 342.2 342.2 0.0 0.1 6.4 2.8 0 043 Screen 18.7 2280 234.5 28.8 0.0 0.8 1.2 1.2 0 054 Light NA Inf 15.0 15.0 0.0 0.0 0.0 0.0 -5 -565 Plant 24.0 Inf 349.3 349.3 74.3 7.3 1.2 1.2 0 076 Heating NA Inf 75.0 75.0 0.0 0.0 0.0 0.0 -50 -5087 Floor 12.1 42000 0.0 225.2 15.4 0.0 1.2 0.1 0 0910Volume T C H111 Outdoors 10.0 Inf 0122 Indoors 25.3 4780 110133 Soil 6.0 Inf 0
After step 7 we return to step 2 and loop through the calculations, step 2 to 7, for a total of
xxxxxxxxxx141Layer T C E E_ A A_ U U_ H H_ SumNetAH21 Sky -10.0 Inf 271.9 0.0 0 0 0.0 0.0 0 0 18484.032 Glass 13.0 8400 336.0 336.0 0 0 6.4 2.8 0 0 -16606.843 Screen 21.5 2280 242.0 29.7 0 0 1.2 1.2 0 0 7970.854 Light NA Inf 15.0 15.0 0 0 0.0 0.0 0 0 -7200.065 Plant 24.0 Inf 349.3 349.3 0 0 1.2 1.2 0 0 26682.076 Heating NA Inf 75.0 75.0 0 0 0.0 0.0 0 0 -45000.087 Floor 12.5 42000 0.0 226.3 0 0 1.2 0.1 0 0 21153.2910$Volumes11Volume T C H SumNetH121 Outdoors 10.0 Inf 0 4740.8132 Indoors 26.6 4780 0 7664.4143 Soil 6.0 Inf 0 111.8
The columns SumNetAH and sumNetH corresponds to the net absorption
When considering the loss to the outdoors, it should be noted that
The total net absorption for any layer
where again we for convenience have left out the emission of short-wave radiation,
Similarly for the three volumes (
We get a total balance of
which again matches the emitted short-wave energy,
Advective heat transfer is effectuated by ventilation. This causes a transfer of energy, in cold climates usually a loss, from the indoors air to the outdoors. This is due to a loss of both sensible heat (the air being colder outside than the inside) and of latent heat (the air being drier outside than inside). The advective heat transfer treated here concerns only the sensible heat while the transfer of latent heat is treated further down (after the water budget has been worked out).
The 4-energy-budget-advection.R script continues the example from above with a simulation time step
Our initial set-up for the budget has been extended with a V column for the volumes to hold
xxxxxxxxxx131Layer T C E E_ A A_ U U_ H H_21 Sky -10 Inf 271.9 0.0 0.0 2.2 0.0 0.0 0 032 Glass 15 8400 344.0 344.0 0.0 0.1 6.4 2.8 0 043 Screen 18 2280 232.3 28.5 0.0 0.8 1.2 1.2 0 054 Light NA Inf 15.0 15.0 0.0 0.0 0.0 0.0 -5 -565 Plant 24 Inf 349.3 349.3 74.3 7.3 1.2 1.2 0 076 Heating NA Inf 75.0 75.0 0.0 0.0 0.0 0.0 -50 -5087 Floor 12 42000 0.0 224.9 15.4 0.0 1.2 0.1 0 0910Volume T C H V111 Outdoors 10 Inf 0 59122 Indoors 25 4780 110 -59133 Soil 6 Inf 0 0
The steps to resolve the energy budget follows those above with the addition of the ventilation flux (column V) in every minor time step. Thus we arrive at this solution for the budget:
xxxxxxxxxx131Layer T C E E_ A A_ U U_ H H_ SumNetAH21 Sky -10.0 Inf 271.9 0.0 0 0 0.0 0.0 0 0 18474.332 Glass 13.0 8400 335.8 335.8 0 0 6.4 2.8 0 0 -17011.443 Screen 21.4 2280 241.7 29.7 0 0 1.2 1.2 0 0 7638.454 Light NA Inf 15.0 15.0 0 0 0.0 0.0 0 0 -7200.065 Plant 24.0 Inf 349.3 349.3 0 0 1.2 1.2 0 0 26293.976 Heating NA Inf 75.0 75.0 0 0 0.0 0.0 0 0 -45000.087 Floor 12.5 42000 0.0 226.3 0 0 1.2 0.1 0 0 20966.6910Volume T C H V SumNetHV111 Outdoors 10.0 Inf 0 0 15239.9122 Indoors 24.7 4780 0 0 -1513.5133 Soil 6.0 Inf 0 0 111.8
Beforehand, the budget resulted in an increase in
The total net absorption of layers is still described by eq.
Again we achieve the expected energy balance,
So far, we have set the
The code needed only little change to implement these changes. This is the outcome of the resulting 5-energy-budget-plant.R script:
xxxxxxxxxx131Layer T C E E_ A A_ U U_ H H_ SumNetAH21 Sky -10.0 Inf 271.9 0.0 0.0 370.6 0.0 0.0 0.0 0.0 18474.832 Glass 13.0 8400 335.8 335.8 239.3 338.9 6.4 2.8 -20.9 32.2 -16989.943 Screen 21.6 2280 242.3 29.8 26.8 273.3 1.2 1.2 4.4 4.4 8193.854 Light NA Inf 15.0 15.0 0.0 0.0 0.0 0.0 -5.0 -5.0 -7200.065 Plant 25.4 Inf 355.9 355.9 0.0 0.0 0.0 0.0 0.0 0.0 24663.776 Heating NA Inf 75.0 75.0 0.0 0.0 0.0 0.0 -50.0 -50.0 -45000.087 Floor 12.5 42000 0.0 226.3 332.5 0.0 1.2 0.1 14.8 -0.6 21650.9910Volume T C H V SumNetHV111 Outdoors 10.0 Inf 20.9 58.1 15263.8122 Indoors 24.8 4780 54.1 -58.1 -1169.0133 Soil 6.0 Inf 0.6 0.0 111.9
The relative humidity was fixed at 90% for these calculations. It can be seen that the plant temperature, previously fixed at
The total energy budget changed only little and is still in balance:
The dominating source of water vapour in the greenhouse is canopy transpiration. The main sinks of water vapour are condensation and ventilation. Condensation on the glass is welcome as it lowers air humidity and thereby lowers the risk of condensation on the plant as well. Condensation on the plants is unwanted as it may lead to disease outbreaks. We consider water condensing on the plants an exception and include only condensation on the glass in the model.
The water film forming on the glass is very thin, only about 16 μm (Pieters el al., 1996). During prolonged condensation (typically during the night) water will run off the glass and end up in the gutter. Evaporation of the water film thus makes only a tiny contribution to the water budget and is left out of the model.
The water budget model consists of three components: transpiration from the canopy, condensation on the inside of the glass, and mass transport of water between indoors and outdoors air.
The figures in this sub-section were generated by the 5-water-budget.R script.
Transpiration

Condensation occurs when the glass temperature falls below the dew point of the indoors air. The saturated water vapour pressure at the temperature of the glass is
The absolute humidity
In our terms,
where

It is seen how warmer air can hold more water vapour.
The saturated absolute humidity only depends on temperature (eqs.
The condensation rate at the glass
with units
where
Pieters et al. (1996) estimated

This estimate of
This figure shows the condensation rate, depending on glass temperature, at indoors temperature

The vertical line at
Ventilation causes mass movement of water vapour between outdoors and indoors air. To calculate the resultant change in indoors absolute humidity
where
The average rate of water lost by mass movement during the time step is
where
This is depicted in the following figure at a ventilation rate of

The cooler outdoors air can hold only little water. Hence, ventilation is an effective means of lowering indoors humidity. The effect is larger with more humid indoors. The flux of water vapour is negative because water is lost from the greenhouse. Since the humid indoors air holds latent heat originally captured by transpiration, ventilation also functions as an indirect route of venting excess heat.
The latent heat carried by water vapour is released during condensation. Knowing the condensation rate at the glass
The heat of vapourisation
The model was extended with a water budget shown as three columns (in g/m2) in the output, Tr (transpration), Cn (condensation) and Mv (mass movement). This is the outcome of the final 7-energy-budget-complete.R script:
xxxxxxxxxx171Layer T C E E_ A A_ U U_ H H_ Cn SumNetAH21 Sky -10.0 Inf 271.9 0.0 0.0 370.6 0.0 0.0 0.0 0.0 0 18474.832 Glass 13.0 8400 335.8 335.8 239.3 338.9 6.4 2.8 -20.9 32.2 2 -16989.943 Screen 21.6 2280 242.3 29.8 26.8 273.3 1.2 1.2 4.4 4.4 0 8193.854 Light NA Inf 15.0 15.0 0.0 0.0 0.0 0.0 -5.0 -5.0 0 -7200.065 Plant 25.4 Inf 355.9 355.9 0.0 0.0 0.0 0.0 0.0 0.0 0 24663.776 Heating NA Inf 75.0 75.0 0.0 0.0 0.0 0.0 -50.0 -50.0 0 -45000.087 Floor 12.5 42000 0.0 226.3 332.5 0.0 1.2 0.1 14.8 -0.6 0 21650.9910Volume T C H V RH SumNetHV111 Outdoors 10.0 Inf 20.9 58.1 60.0 15263.8122 Indoors 24.8 4780 54.1 -58.1 98.1 -1169.0133 Soil 6.0 Inf 0.6 0.0 NA 111.91415Volume Tr Cn Mv161 Outdoors 0.00 0.000 2.532172 Indoors 16.12 -0.009 -2.532
xxxxxxxxxx171Layer T C E E_ A A_ U U_ H H_ Cn SumNetAH SumCn21 Sky -10.0 Inf 271.9 0.0 0.0 370.6 0.0 0.0 0.0 0.0 0 18474.8 0.032 Glass 13.0 8400 335.8 335.8 239.3 338.9 6.4 2.8 -20.9 32.2 2 -16989.9 10.843 Screen 21.6 2280 242.3 29.8 26.8 273.3 1.2 1.2 4.4 4.4 0 8193.8 0.054 Light NA Inf 15.0 15.0 0.0 0.0 0.0 0.0 -5.0 -5.0 0 -7200.0 0.065 Plant 25.4 Inf 355.9 355.9 0.0 0.0 0.0 0.0 0.0 0.0 0 24663.7 0.076 Heating NA Inf 75.0 75.0 0.0 0.0 0.0 0.0 -50.0 -50.0 0 -45000.0 0.087 Floor 12.5 42000 0.0 226.3 332.5 0.0 1.2 0.1 14.8 -0.6 0 21650.9 0.0910Volume T C H V RH SumNetHV111 Outdoors 10.0 Inf 20.9 58.1 60.0 15263.8122 Indoors 24.8 4780 54.1 -58.1 98.1 -1169.0133 Soil 6.0 Inf 0.6 0.0 NA 111.91415Volume Tr Cn Mv161 Outdoors 0.000 0.000 2.532172 Indoors 8.060 -0.004 -2.532
The output shows the outcome after one time step Tr column) was transpired by the crop. Meanwhile ventilation got rid of Mv column) of the the transpired water.
The condensed water amounted to Cn column). Multiplication by the latent heat of evaporation
which appears in the SumCn column for the glass layer. The increase in glass temperature caused by condensation alone, taking the heat capacity of the glass layers
Indoors humidity was initialised high at 90% but increased even more to 98.1%, despite the lower outdoors humidity at 60%. In a real greenhouse, ventilation would need to be increased to push humidity down.
The total energy budget changed very little and remained in balance:
It is worth noting that the latent heat, which escaped by ventilation, is not part of the energy budget. In this example it amounted to
These
We use the Ideal Gas Law earlier on (eq.
As an example, with greenhouse dimensions of
or
or
However, the plants will take up CO2 which must be compensated for to keep up the CO2 concentration. For example, a tomato crop grown at a leaf area index of
or
Meanwhile, CO2 is lost to the outdoors even with all windows closed due to leakage, maybe at a rate of some
The whole CO2 budget can be expressed in the differential equation,
with
Integration gives us the following solution of the
The figure below illustrates eq.
The time course of the indoors CO2 is shown on the y-axis as

Note that
In the full model the CO2 setpoint, controller and actuator will collaborate to adjust the injection rate, so that the indoors CO2 concentration is maintained at the setpoint. The injection rate
and
with greenhouse area
The combined energy and water budget is a central part of the model. It is where most computation takes place and where most execution time is spent. Therefore it is worth optimising its performance. This can be achieved by varying the number of minor time steps
Set
Compute the budget for one minor time step of length
If the max. temperature change exceeds a critical limit
where
Complete the budget computation for the remaining
Re-calculate
This algorith will adjust
The photosynthesis model is identical to the implementation in the Photosyn function found in the plantecophys R package (Duursma, 2015). The Photosyn function was re-coded in C++ keeping only the functionality needed for our purpose. However, boundary layer conductivity
where
In the overview of variables and parameters below, the mathematical symbols used in this treatise (e.g., PPFD). The re-coded versions of the original Photosyn functions can be found in the photosynthesis.R script and, equivalently, in the photosynthesis.cpp source code. All m2 units are per m2 leaf. This is stated explicitly only where there is room for confusion.
Environmental and plant variables:
Ca)
PPFD)
RH)
Tleaf)
GS)
GB)
Obligatory species-specific parameters:
Jmax)
Vcmax)
GammaStar)
Km)
Rd0)
Optional species-specific parameters (with default values):
alpha)
theta)
Temperature response of
EaJ)
EdVJ)
delsJ)
Temperature response of
EaV)
EdVC)
delsJ)
Respiration rate:
Q10)
Function outputs:
Ci
ALEAF
Aj)
Ac)
Rd)
The photosynthesis.R script produces this figure to illustrate the output of the photosynthesis function (parameter values can be found in the code):

We see the expected form of the light response curve with positive effects of light, temperature and CO2. Internally, the model lets the more limiting process, electron transport or carboxylation rate (as judged from
The energy budget model computes the total PAR absorbed by the plant canopy per m2 ground over one simulation time step, most of it coming from above
By correcting for the leaf area index
However, the leaf photosynthesis model takes incident PAR
where
The immediate outputs from the leaf photosynthesis model are all per leaf area, e.g., the net photosynthetic rate
With a basic parameter setting for the canopy model, photosynthesis.R script) the canopy photosynthesis

The self-shading of the canopy brings light intensity down by a factor of
Another factor that creates uncertainty in the photosynthesis model is the uncertainty of the boundary layer resistance (
The gradients of light and
If the model is used to explore photosynthesis under different scenarios (e.g., different climate control strategies), the estimated photosynthesis can be used to compare their relative performance. However, the uncertainties and unknowns should be taken into account. The installation of fans will reduce
Traditionally, greenhouse climate is controlled by two temperature setpoints: one for ventilation

The humidity is controlled indirectly through manipulation of the temperature setpoints, e.g., if it is too humid then the ventilation setpoint is lowered.
In the model, greenhouse air temperature
If it is too hot
If heating is on, we are heating needlessly and must turn down the heating:
Decrease the pipe temperature
If heating is off, we must turn up ventilation:
Increase the ventilation rate
If it is too cold
If ventilation is on, we are cooling needlessly and must turn down ventilation:
Decrease the ventilation rate
If ventilation is off, we must turn up heating:
Increase the pipe temperature
If greenhouse temperature is within bounds:
Keep current pipe temperature
The default corrections of pipe temperature
where the default rates of change are